﻿using System;
using QuailDashboard.View.Data;
using QuailDashboard.View.Helpers;

namespace QuailDashboard.View.Models
{
    /// <summary>
    /// List of TestClassName objects
    /// </summary>
    public class TestClassHeirarchyList : SortableObservableCollection<TestClassHeirarchy>
    {
        private readonly TestClassHeirarchy _parent;

        /// <summary>
        /// Initializes a new instance of the <see cref="TestClassHeirarchyList"/> class.
        /// </summary>
        /// <param name="parent">The parent test class.</param>
        public TestClassHeirarchyList(TestClassHeirarchy parent)
        {
            _parent = parent;
        }

        /// <summary>
        /// Finds a test class node using a given test name (may be a partial class name: eg AllTests.Employer)
        /// </summary>
        /// <param name="fulltestclass">the test class name</param>
        /// <returns>the found test item</returns>
        public TestClassHeirarchy FindTestClass(string fulltestclass)
        {
            var classnames = fulltestclass.Split('.');

            var list = this;
            TestClassHeirarchy found = null;
            foreach (var classname in classnames)
            {
                var wasfound = false;
                foreach (var item in list)
                {
                    if (item.Name == classname)
                    {
                        found = item;
                        list = found.ChildList;
                        wasfound = true;
                        break;
                    }
                }

                if (!wasfound)
                    return null;
            }

            return found;
        }

        /// <summary>
        /// Adds a test to the list
        /// </summary>
        /// <param name="test">the test to add</param>
        public void AddTestClass(RunStatusResultWrapper test)
        {
			if (_parent != null)
				throw new Exception("AddTest can only be called at the root level");

            var items = test.CompleteTestClassName.Split('.');

            TestClassHeirarchy tch = null;
            var list = this;

            foreach (var item in items)
            {
                tch = list.SafeAdd(item.Trim());
                list = tch.ChildList;
            }

            if (tch == null)
                throw new Exception("Unable to add test: " + test.FullName);

            tch.AddTest(test);
        }

        /// <summary>
        /// Sets all items in the list to stale
        /// </summary>
        public void SetTestsStale()
        {
            foreach (var item in this)
                item.ClearTests();
        }

        /// <summary>
        /// Removes stale items from the list
        /// </summary>
        public void RemoveTestClassesWithoutTests()
        {
            var i = 0;
            while (i < Count)
            {
                var item = this[i];
                if (!item.HasTests)
                {
                    RemoveAt(i);
                }
                else
                {
                    item.ChildList.RemoveTestClassesWithoutTests();
                    i++;
                }
            }
        }

        private TestClassHeirarchy SafeAdd(string name)
        {
            foreach (var item in this)
            {
                if (item.Name == name)
                    return item;
            }

            return AddAndSort(new TestClassHeirarchy(_parent, name));
        }

        private TestClassHeirarchy AddAndSort(TestClassHeirarchy newitem)
        {
            Add(newitem);
            Sort(Comparer);
            return newitem;
        }

        private static int Comparer(TestClassHeirarchy left, TestClassHeirarchy right)
        {
            return string.Compare(left.Name, right.Name, StringComparison.CurrentCultureIgnoreCase);
        }
    }
}
